/**
 * 
 */
package com.cloudcast.client.controller;

import java.util.HashMap;
import java.util.Map;

import com.cloudcast.client.presenter.Presenter;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.History;

/**
 * @author Samuel García Martínez <in0de>
 *
 */
public abstract class AbstractController extends AbstractResponsible implements Controller {
	
	private Map<String, Responsible> responsibles;
	
	private Responsible actualResponsible;
	
	protected AbstractController(Controller parent, HandlerManager eventBus) {
		super(parent, eventBus);
		this.responsibles = new HashMap<String, Responsible>();
		
		registerResponsibles(this.responsibles);
	}
	
	public void invokeView(String viewId) throws ControllerException {
		Responsible responsible = responsibles.get(viewId);
		
		if(responsible == null)
			throw new ControllerException(this, "Not responsible found for token " + viewId);
		
		/* 
		 * if the controller has a Presenter associated it, is invoked once 
		 */
		Boolean invokeControllerPresenter = getParent() != null && !getParent().isActualResponsible(this);
				
		if(invokeControllerPresenter)
			invokeControllerPresenter();
				
		if(responsible instanceof Controller) 
			((Controller)responsible).invokeView(viewId);
		else if(responsible instanceof Presenter) 
			((Presenter)responsible).go(getContainer());
		else
			throw new ControllerException(this, "Unknown responsible type for token " + viewId);
		
		this.setActualResponsible(responsible);
	}		

	protected void invokeControllerPresenter() {
		LayoutContainer container = null;
		
		if(getParent() != null)
			container = getParent().getContainer();
		
		this.getPresenter().go(container);
	}
	
	protected void setActualResponsible(Responsible responsible) {
		if(!responsible.equals(this.actualResponsible)) {
			responsible.bind(this);
			
			if(this.actualResponsible != null)
				this.actualResponsible.unbind(this);
			
			this.actualResponsible = responsible;
		}
	}
	
	protected abstract void registerResponsibles(Map<String, Responsible> responsibles);
		
	public Boolean isActualResponsible(Responsible responsible) {
		return (actualResponsible == null)? false : actualResponsible.equals(responsible);
	}
	
	protected Map<String, Responsible> getResponsibles() {
		return this.responsibles;
	}
	protected Responsible getResponsible(String viewId) {
		return this.responsibles.get(viewId);
	}
	
	public String getActualViewId() {
		return History.getToken();
	}
	
	@Override
	public Controller getParent() {
		return (Controller)super.getParent();
	}
	
}
